package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tbit.common.entity.view.Result;
import com.tbit.common.utils.TbitHttpServiceUtil;
import com.tbit.uqbike.constant.*;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.RideOrderRefundDTO;
import com.tbit.uqbike.object.pojo.vo.FeeAppealInfoVO;
import com.tbit.uqbike.object.pojo.vo.RideLogDetailsVO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.service.business.*;
import com.tbit.uqbike.webmanager.dao.capital.RefundLogDao;
import com.tbit.uqbike.webmanager.dao.capital.RideLogDetailsDao;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.log.RefundOpeLogDao;
import com.tbit.uqbike.webmanager.dao.log.UserRefundLogDao;
import com.tbit.uqbike.webmanager.sms.ApiStoreMsgUtils;
import com.tbit.uqbike.webmanager.sms.ClzySmsAuthUtil;
import com.tbit.uqbike.webmanager.util.Assert;
import com.tbit.uqbike.webmanager.util.BeanUtils;
import com.tbit.uqbike.webmanager.util.DateUtils;
import com.tbit.uqbike.webmanager.util.csv.CsvExportUtils;
import com.tbit.uqbike.webmanager.util.csv.annotations.AsyncDownload;
import com.tbit.uqbike.webmanager.util.csv.entity.ExportHandler;
import com.tbit.uqbike.webmanager.util.weixin.WeixinPay;
import com.tbit.uqbike.webmanager.util.weixin.WeixinPayUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author HZW
 * @ClassName OrderFeeAppealServiceImpl
 * @Description 订单费用申诉业务层
 * @date 2021/12/20 11:22
 * @Version 1.0
 */
@Slf4j
@Service("orderFeeAppealService")
public class OrderFeeAppealServiceImpl implements OrderFeeAppealService {
    @Resource
    private OrderFeeAppealDao orderFeeAppealDao;
    @Resource
    private UserDao userDao;
    @Resource
    private RideLogDao rideLogDao;
    @Resource
    private RechargeDao rechargeDao;
    @Resource
    private WeixinPayConfigDao weixinPayConfigDao;
    @Resource
    private UserAccountLogDao userAccountLogDao;
    @Resource
    private RefundOpeLogDao refundOpeLogDao;
    @Resource
    private UserRefundLogDao userRefundLogDao;
    @Resource
    private SmsAuthConfigDao smsAuthConfigDao;
    @Resource
    private AccountDao accountDao;
    @Autowired
    private RefundService refundService;
    @Autowired
    private RefundLogDao refundLogDao;
    @Autowired
    private GiftCardUserService giftCardUserService;
    @Autowired
    private UsermsgDao usermsgDao;
    @Resource
    private SmsAuthConfigServiceImpl smsAuthConfigService;
    @Resource
    private RefundOrderService refundOrderService;
    @Autowired
    private CsvExportUtils csvExportUtils;
    @Resource
    private RideLogDetailsService rideLogDetailsService;


    @Override
    public List<FeeAppeal> getInfo(FeeAppeal feeAppeal) {
        List<FeeAppeal> list = orderFeeAppealDao.getInfo(feeAppeal);
        //设置其它信息
        this.setFeeAppealInfo(list,feeAppeal);
        return list;
    }

    @Override
    public Result<MachineRideLog> queryOrderInfoByOrderNo(String orderNo) {
        RideLog rideLog = rideLogDao.getByOrderNO(orderNo);
        if (null == rideLog) {
            throw new BaseException("无订单记录");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", rideLog.getMachineId());
        map.put("orderNO", orderNo);
        map.put("start", 0);
        map.put("rowCount", 10);
        MachineRideLog machineRideLog = rideLogDao.getByMachineId(map).stream().findFirst().orElse(null);
        return Result.success(machineRideLog);
    }

    @Override
    public Boolean handle(FeeAppeal feeAppeal, LoginInfo login) throws ParseException {
        boolean flag = false;
        Map<String, Object> map = new HashMap<>(6);
        Date nowDate = DateUtils.getNowDate();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //查询退款的订单
        RideLog rideLog = rideLogDao.getByOrderNO(feeAppeal.getOrderNO());
        if (null == rideLog) {
            throw new BaseException("无订单记录");
        }

        //增加 原路退还 选项
        if (feeAppeal.getState() == 2 && feeAppeal.getCompensationId() == 3) {

            RideOrderRefundDTO rideOrderRefundDTO = new RideOrderRefundDTO();
            rideOrderRefundDTO.setUserId(rideLog.getUserId());
            rideOrderRefundDTO.setOrderNO(rideLog.getOrderNO());
            rideOrderRefundDTO.setRefundMoney(feeAppeal.getRefundMoney());
            rideOrderRefundDTO.setFineMoney(feeAppeal.getFineMoney());
            rideOrderRefundDTO.setGiftMoney(feeAppeal.getGiftMoney());
            rideOrderRefundDTO.setRemark(feeAppeal.getResult());
            rideOrderRefundDTO.setSendMsg(0);
            rideOrderRefundDTO.setPsw(feeAppeal.getOperaPsw());

            Result result = refundService.rideOrderRefund(login, rideOrderRefundDTO);
            if (!(HttpStatus.SUCCESS == result.getCode())) {
                throw new BaseException(result.getMsg());
            }

            flag = true;
            log.info("执行到此:" + flag);
        }
        //4 礼品卡

        /**补偿方案为退款金额原路返回*/
        if (feeAppeal.getState() == 2 && feeAppeal.getCompensationId() == 0) {
            Assert.notNull(feeAppeal.getMoney(), "ver.money.notNull");
            /**申诉的订单支付金额小于等于0，不让退款*/
            if (rideLog.getMoney() <= 0) {
                throw new BaseException("申诉的订单支付金额必须大于0");
            }
            map.put("userId", feeAppeal.getUserId());
            /**获取用户的所有充值记录*/
            List<Recharge> rechargeList = rechargeDao.getByTimeOrderBy(map);
            /**退款金额*/
            Integer refundMoney = Integer.parseInt(feeAppeal.getMoney().toString());
            Double reMoney = 0.0;
            for (Recharge recharge : rechargeList) {
                /**获取充值类型*/
                Integer rechargeType = recharge.getRechargeType();
                /**微信退款判断订单的时效性*/
                if (recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_APP) || recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_XCX)) {
                    if (DateUtils.MoreThenMonth(new Date(), formatter.parse(recharge.getPayTime()), 12)) {
                        throw new BaseException("充值订单时间大于一年,无法退款");
                    }
                }
                /**支付宝退款判断订单的时效性*/
                if (recharge.getType().equals(RechargeConstant.RECHARGE_ZFB_APP) || recharge.getType().equals(RechargeConstant.RECHARGE_ZFB_XCX)) {
                    if (DateUtils.MoreThenMonth(new Date(), formatter.parse(recharge.getPayTime()), 3)) {
                        throw new BaseException("充值订单时间大于三个月,无法退款");
                    }
                }

                /**生成微信退款订单号*/
                String returnNonceStr = WeixinPayUtil.getReturnNonceStr();
                Integer accountId = recharge.getAccountId();
                int platformType = 0;
                /**如果退款的金额大于充值的金额，这笔订单全退*/
                if (refundMoney >= recharge.getMoney()) {
                    //判断是微信还是支付宝
                    if (recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_APP) || recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_XCX)) {
                        //获取平台微信支付信息
                        Map<String, Object> params = new HashMap<>(3);
                        params.put("accountId", accountId);
                        params.put("type", recharge.getType());
                        WeixinPayConfig weixinPayConfig = weixinPayConfigDao.getByAccountId(params);
                        /**调用微信的退款接口*/
                        flag = WeixinPay.return_deposit(weixinPayConfig, recharge.getOrderNO(), returnNonceStr, String.valueOf(recharge.getMoney().intValue()), String.valueOf(recharge.getMoney().intValue()));
                    }
                    /**如果小于充值的金额，则将退款的金额退回*/
                } else {
                    //判断是微信还是支付宝
                    if (recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_APP) || recharge.getType().equals(RechargeConstant.RECHARGE_WEIXIN_XCX)) {
                        //获取平台微信支付信息
                        Map<String, Object> params = new HashMap<>(3);
                        params.put("accountId", accountId);
                        params.put("type", recharge.getType());
                        WeixinPayConfig weixinPayConfig = weixinPayConfigDao.getByAccountId(params);
                        flag = WeixinPay.return_deposit(weixinPayConfig, recharge.getOrderNO(), returnNonceStr, String.valueOf(refundMoney), String.valueOf(recharge.getMoney().intValue()));
                    }
                }
                /**退款的金额大于充值的金额，则这个记录的退款金额是这笔充值金额*/
                if (refundMoney >= recharge.getMoney()) {
                    reMoney = recharge.getMoney();
                    refundMoney = refundMoney - recharge.getMoney().intValue();
                } else {
                    reMoney = Double.parseDouble(refundMoney.toString());
                    refundMoney = 0;
                }

                if (flag) {
                    String orderNO = recharge.getOrderNO();
                    log.info("金额退还成功，商户平台订单号=" + orderNO);
                    Integer userId = recharge.getUserId();
                    User user = userDao.getByUserId(userId);

                    //用户充值金额退款
                    if (RechargeConstant.recharge_pay.equals(rechargeType) && Boolean.FALSE.equals(recharge.getDeposit())) {
                        log.info("用户充值金额退款");
                        /**记录余额变动日志*/
                        UserAccountLog userAccountLog = new UserAccountLog(userId, accountId, WeixinConstant.PRACTICAL_MONEY, WeixinConstant.FEE_DEDUCTION, reMoney.intValue(), nowDate, login.context.getMessage("user_refund_deduction"));
                        userAccountLogDao.insert(userAccountLog);
                    } else if (RechargeConstant.recharge_returnBike.equals(rechargeType)) {
                        /**记录余额变动日志*/
                        UserAccountLog userAccountLog = new UserAccountLog(userId, accountId, WeixinConstant.PRACTICAL_MONEY, WeixinConstant.FEE_DEDUCTION, reMoney.intValue(), nowDate, "订单申诉退款");
                        userAccountLogDao.insert(userAccountLog);
                        /**记录退款，后期结算减去该退款*/
                        RefundOpeLog refundOpeLog = new RefundOpeLog(accountId, reMoney.intValue(), nowDate, userId, user.getPhone(), login.getAccountUserId(), login.getPhone(), orderNO, recharge.getRechargeType());
                        refundOpeLogDao.insert(refundOpeLog);
                    }

                    /**记录退款记录*/
                    UserRefundLog userRefundLog = new UserRefundLog(accountId, userId, rechargeType, platformType, orderNO, returnNonceStr, nowDate, recharge.getMoney(), reMoney, recharge.getPayTime());
                    userRefundLogDao.insertUserRefundLog(userRefundLog);

                    /**如果退款的金额小于等于0，则退款操作结束*/
                    if (refundMoney <= 0) {
                        break;
                    }
                }
            }
            /**补偿方案为退虚拟金额给用户*/
        } else if (feeAppeal.getState() == 2 && feeAppeal.getCompensationId() == 1) {
            Assert.notNull(feeAppeal.getRefundMoney(), "ver.money.notNull");
            Integer money = (int) (feeAppeal.getRefundMoney() * 100);
            /**判断退款金额是否超过可退金额*/
            if (money > rideLog.getMoney()) {
                throw new BaseException(SystemCodeEnum.SUPER_RETREAT);
            }
            User user = userDao.getByUserId(feeAppeal.getUserId());
            Integer newMoney = money;
            Integer newRideMoney = null;
            try {
                int rideMoney = user.getRideMoney();
                if (rideMoney > 0) {
                    //用户有欠费，优先补回欠费
                    if (rideMoney >= money) {
                        //欠费大于等于退款金额，欠费补交，余额不加
                        newRideMoney = rideMoney - money;
                        newMoney = 0;
                    } else {
                        //欠费小于退款金额，欠费补交，余额加上补完欠费后的
                        newRideMoney = 0;
                        newMoney = money - rideMoney;
                    }
                }
                map.put("rideMoney", newRideMoney);
                map.put("money", newMoney);
                map.put("userId", feeAppeal.getUserId());
                map.put("updateTime", formatter.format(new Date()));
                /**退款金额到用户余额中*/
                userDao.updateMoney(map);
                /**记录余额变动日记*/
                UserAccountLog userAccountLog = new UserAccountLog(feeAppeal.getUserId(), feeAppeal.getAccountId(), WeixinConstant.PRACTICAL_MONEY, WeixinConstant.FEE_RECHARGE, money, nowDate, "订单申诉增加余额");
                userAccountLogDao.insert(userAccountLog);
            } catch (Exception e) {
                throw new BaseException(SystemCodeEnum.OPERATIOBMN_FAILED);
            }
        } else if (feeAppeal.getState() == 2 && feeAppeal.getCompensationId() == 4) {
            //退款到礼品卡
            Assert.notNull(feeAppeal.getRefundMoney(), "退款金额不能为空");
            Assert.notNull(feeAppeal.getFineMoney(), "罚款金额不能为空");
            if (feeAppeal.getGiftMoney() == null) {
                //兼容运维端未升级不传礼品卡金额情况
                feeAppeal.setGiftMoney(0L);
            }

            int money = (int) (feeAppeal.getFineMoney() + feeAppeal.getRefundMoney());
            if (money > rideLog.getMoney()) {
                throw new BaseException(SystemCodeEnum.SUPER_RETREAT);
            }

            /*礼品金不能超过该订单使用礼品金*/
            RideLogDetailsVO rideLogDetailsVO = rideLogDetailsService.queryByOrderId(feeAppeal.getOrderNO());
            if (Objects.nonNull(rideLogDetailsVO) ){
                if ((int)(NumberUtil.mul(100D,rideLogDetailsVO.getReturnableGiftCardMoney().doubleValue())) < feeAppeal.getGiftMoney()) {
                    throw new BaseException(SystemCodeEnum.SUPER_RETREAT);
                }
            }

            giftCardUserService.recharge(rideLog.getAccountId(), rideLog.getUserId(), money, "费用申诉退至用户礼品卡", login);
        }

        feeAppeal.setHandleTime(formatter.format(new Date()));
        try {
            /**向客户发送消息*/
            if (feeAppeal.getIsSend().equals(1)) {
                /**获取运营商id*/
                Account brand = accountDao.getAgentId(feeAppeal.getAccountId());
                /**品牌id*/
                Integer brandId = brand.getParentId();
                /**获取短信配置*/
                SmsAuthConfig smsAuthConfig = smsAuthConfigDao.selectSmsConfig(brandId);
                //优驱api配置
                BrandRemoteConfig brandRemoteConfigDB = smsAuthConfigService.getBrandRemoteConfig(brandId,
                        BrandRemoteConfigConstant.TBIT_CONFIG);
                if (!NullUtils.isEmpty(smsAuthConfig)) {
                    /**寻程发送短信*/
                    ApiStoreMsgUtils.refundSend(feeAppeal.getPhone(), "你申诉的订单已经完成，请前往小程序查看！", smsAuthConfig.getSmsCodeKey(), Integer.valueOf(smsAuthConfig.getModelId()));
                } else if (Objects.nonNull(brandRemoteConfigDB)) {
                    String templateId = smsAuthConfigService.getBrandRemoteConfigValue(brandId, BrandRemoteConfigConstant.SMS_ORDER_FEE);
                    boolean result = false;
                    if (StringUtils.isNotEmpty(templateId)) {
                        //优驱api发送短信
                        String key = brandRemoteConfigDB.getParamKV();
                        String[] strings = key.split("&");
                        result = TbitHttpServiceUtil.sendSms(strings[0].substring(strings[0].indexOf("=") + 1),
                                strings[1].substring(strings[1].indexOf("=") + 1)
                                , strings[2].substring(strings[2].indexOf("=") + 1), feeAppeal.getPhone(), "", Integer.valueOf(templateId));
                    }
                    if (!result) {
                        log.info("手机号：{}订单费用申诉提醒优驱api短信发送失败", feeAppeal.getPhone());
                    }
                }else {
                    Map<String, Integer> noteMap = new HashMap<>();
                    noteMap.put("accountId", brandId);
                    noteMap.put("configType", 4);
                    Account brandArea = accountDao.getByAccountId(brandId);
                    BrandRemoteConfig brandRemoteConfig = smsAuthConfigDao.getByConfigType(noteMap);
                    if (brandRemoteConfig != null) {
                        String[] strings = brandRemoteConfig.getParamKV().split("&");
                        String accounts = strings[0].substring(strings[0].indexOf("=") + 1);
                        String password = strings[1].substring(strings[1].indexOf("=") + 1);
                        ClzySmsAuthUtil.sendSms(accounts, password, "【" + brandArea.getName() + "】" + "你申诉的订单已经完成，请前往小程序查看！", feeAppeal.getPhone());
                    }
                }
            }
            /**修改状态*/
            Integer num = orderFeeAppealDao.updateState(feeAppeal);
            if (num > 0) {
                flag = true;
                usermsgDao.insert(new Usermsg(rideLog.getUserId(), "申述进度更新通知", "您申述的已完成，如有疑问，请您联系客服继续处理，感谢您的支持。"));
            }
        } catch (Exception e) {
            log.error("第一次", e);
            throw new BaseException(SystemCodeEnum.OPERATIOBMN_FAILED);
        }
        log.info("执行到最后:" + flag);
        return flag;
    }


    /**
     * @description: 查询总数
     * @author: mo.shanyong
     * @date: 2024/11/28 17:03
     * @return: int
     */
    @Override
    public int getBigExcelCount(FeeAppeal feeAppeal) {
        return orderFeeAppealDao.getBigExcelCount(feeAppeal);
    }
    /**
     * @description: 大数据量导出
     * @author: mo.shanyong
     * @date: 2024/11/28 17:05
     * @param: feeAppeal
     * @param: count 总数
     */
    @AsyncDownload(defaultFileName = "订单费用申诉数据")
    @Override
    public Result bigExcelInfo(FeeAppeal feeAppeal) {
        log.info("订单费用申述大数据量导出------->feeAppeal:{}", JSON.toJSONString(feeAppeal));
        int count = feeAppeal.getCount();
        String fileName = StringUtils.isNotBlank(feeAppeal.getFileName()) ? feeAppeal.getFileName()
                : UUID.randomUUID().toString().replace("-","");
        File tempFile = csvExportUtils.getTempFile();
        try {
            ExportHandler<FeeAppeal> exportHandler = baseEntity -> {
                FeeAppeal appeal = BeanUtils.copyProperties(feeAppeal, FeeAppeal.class);
                appeal.setStartId(baseEntity.getStartId());
                appeal.setEndId(baseEntity.getEndId());
                List<FeeAppeal> list = orderFeeAppealDao.getBigExcelInfo(appeal);
                list.forEach(feeAppeal1 -> {
                    feeAppeal1.setMoney(feeAppeal1.getMoney() > 0 ? feeAppeal1.getMoney()/100 : feeAppeal1.getMoney());
                });
                //设置其它信息
                this.setFeeAppealInfo(list,appeal);
                return list;
            };
            Integer maxId = orderFeeAppealDao.getBigExcelMaxAppealId(feeAppeal);
            Integer minId = orderFeeAppealDao.getBigExcelMinAppealId(feeAppeal);
            File file = csvExportUtils.exportBigCsvUseDynamicId(exportHandler, FeeAppeal.class, count, tempFile, fileName, maxId, minId);
            //压缩包名称
            String zipFileName = UUID.randomUUID().toString().replace("-","");
            String url = csvExportUtils.uploadZip(tempFile, zipFileName, file);
            return Result.success(url);
        }finally {
            FileUtil.del(tempFile);
        }
    }

    /**
     * @description: 设置订单费用申诉的其它信息
     * @author: mo.shanyong
     * @date: 2024/11/28 19:45
     * @param: list
     */
    private void setFeeAppealInfo(List<FeeAppeal> list,FeeAppeal feeAppeal){
        List<Account> accountList = accountDao.getByAccountIds(feeAppeal.getAccountIds());
        Map<Integer, Account> accountMap = accountList.stream().collect(Collectors.toMap(Account::getAccountId, account -> account));
        //关联骑行日志表的费用明细
        if (!list.isEmpty()) {
            List<String> orderNOs = list.stream().map(FeeAppeal::getOrderNO).distinct().collect(Collectors.toList());

            List<List<String>> orderNoList = CollUtil.split(orderNOs, 1000);

            // 分批查询，防止数据量过大 In 语句过长，导致查询失败
            List<RefundOrder> byBusinessNoList = new ArrayList<>();
            List<RideLog> rideLogs = new ArrayList<>();
            List<RefundLog> refundLogs = new ArrayList<>();
            for (List<String> orderNos : orderNoList) {
                rideLogs.addAll(rideLogDao.getListByOrderNOs(orderNos));
                refundLogs.addAll(refundLogDao.selectList(new LambdaQueryWrapper<RefundLog>().in(RefundLog::getOrderId, orderNos)));
                byBusinessNoList.addAll(refundOrderService.getByBusinessNoList(orderNos));
            }

            Map<String, Double> refundedMoneyMap = refundLogs
                    .stream()
                    .filter(x -> x.getChangeType() == RefundLogConstant.REFUND_OF_CYCLING_EXPENSES || x.getChangeType() == RefundLogConstant.USER_PENALTY_REFUND)
                    .collect(Collectors.groupingBy(RefundLog::getOrderId, Collectors.summingDouble(RefundLog::getChangeMoney)));

            Map<String, RideLog> rideLogMap = rideLogs.stream().collect(Collectors.toMap(RideLog::getOrderNO, v -> v));

            for (FeeAppeal appeal : list) {
                RideLog rideLog = rideLogMap.get(appeal.getOrderNO());
                appeal.setRefundedMoney(refundedMoneyMap.getOrDefault(appeal.getOrderNO(), 0D) / 100);
                if (rideLog != null) {
                    appeal.setRideRemark(rideLog.getRemark());
                    appeal.setMachineId(rideLog.getMachineId());
                    appeal.setUserCode(rideLog.getUserCode());
                }
                appeal.removeSpecialCharacters();
                if (accountMap.containsKey(appeal.getAccountId())) {
                    appeal.setAccountName(accountMap.get(appeal.getAccountId()).getName());
                }

                if (CollectionUtil.isNotEmpty(byBusinessNoList)) {
                    Map<String, List<RefundOrder>> map = byBusinessNoList.stream().collect(Collectors.groupingBy(RefundOrder::getBusinessNO));
                    List<RefundOrder> refundOrders1 = map.get(appeal.getOrderNO());
                    if (CollectionUtil.isEmpty(refundOrders1)) {
                        continue;
                    }
                    // 过滤出退款中状态
                    Integer refundStatus = refundOrders1.stream()
                            .filter(order -> order.getRefundStatus() == 0)
                            .findFirst()
                            .map(order -> 0)
                            .orElse(null);
                    appeal.setRefundStatus(refundStatus);
                }
            }
        }
    }

    @Override
    public FeeAppealInfoVO getAppealStats(Integer userId) {
        Integer rideLogCount = rideLogDao.selectRideLogCountByUserId(userId);
        FeeAppealInfoVO appealStats = orderFeeAppealDao.getAppealStats(userId);
        appealStats.setRideLogCount(rideLogCount);
        return appealStats;
    }
}
